package cn.tedu.micro.demo.emqx.config;

import cn.tedu.micro.demo.emqx.mqtt.MqttClientCallback;
import lombok.extern.slf4j.Slf4j;
import org.eclipse.paho.client.mqttv3.MqttClient;
import org.eclipse.paho.client.mqttv3.MqttConnectOptions;
import org.eclipse.paho.client.mqttv3.persist.MemoryPersistence;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.util.UUID;

/**
 * 通过配置类 创建一个emqx底层java客户端连接对象
 * MqttClient
 */
@Configuration
@Slf4j
public class MqttClientConfiguration {
    @Autowired
    private MqttClientCallback mqttClientCallback;
    /**
     * 1.读取在yaml中properties中 提供的自定义的属性 address username password
     * 2.手动初始化一个MqttClient的连接对象 用来操作和管理emqx
     */
    //charging.emqx.address
    @Value("${charging.emqx.address}")
    private String address;
    //charging.emqx.username
    @Value("${charging.emqx.username}")
    private String username;
    //charging.emqx.password
    @Value("${charging.emqx.password}")
    private String password;
    //charging.emqx.groupName
    @Value("${charging.emqx.groupName}")
    private String groupName;
    @Bean
    public MqttClient mqttClient(){
        MqttClient mqttClient=null;
        try{
            //1.先new一个对象,根据构造方法 传递参数 address(连谁),clientId(每个客户端对象id唯一),持久化方式(选择内存持久化)
            mqttClient=new MqttClient(address, UUID.randomUUID().toString(),new MemoryPersistence());
            //2.给链接对象 设置一些选项和参数options
            MqttConnectOptions options=new MqttConnectOptions();
            //2.1 连接根据address联通emqx服务端 需要权限username
            options.setUserName(username);
            //2.2 设置密码
            options.setPassword(password.toCharArray());
            //2.3 连接的超时时间 单位秒 客户端会在创建好了之后,建立与emqx broker通信连接,客户端将会在连接不成功,等待超时时间,选择结束
            //当前客户端默认30秒 我们可以自定义,一般会缩小
            options.setConnectionTimeout(15);
            //2.4 设置心跳或者保活间隔,每当客户端建立好了连接之后,服务端会收到这个间隔时间的请求,判断客户端是或者的,超过这个时间1.5倍就判断
            //客户端失效,连接会从服务端broker断开 单位也是秒
            options.setKeepAliveInterval(30);
            //2.5 设置清空会话session.为了避免多个客户端并发连接broker,复用session会话数据时,新的客户端拿到老的客户端遗留数据,每次建立
            //连接复用的session必须清空,如果客户端是为了恢复曾经断开的一个会话,就可以设置false
            options.setCleanSession(true);
            //2.6设置客户端自动重连,因为客户端很可能是物联网设备,经常会断网,重连,所以我们也希望客户端程序,可以在断开之后,重新连接
            //服务端一旦发现客户端断开连接,不会立即删除session,而是在最大的超时时间timeout之前,不断每秒种重连
            options.setAutomaticReconnect(true);
            //3.mqttClient配置这个选项对象,建立连接
            //4.mqttClient设置回调函数
            mqttClient.setCallback(mqttClientCallback);
            mqttClient.connect(options);
            //5.成功创建连接后 使用客户端监听主题 测试让客户端订阅主题topic1 和 topic2
            mqttClient.subscribe("topic01");
            mqttClient.subscribe("$share/group1/topic02");
            //订阅topic03 共享 不同组共享订阅
            mqttClient.subscribe("$share/"+groupName+"/topic03");
        }catch (Exception e){
            log.error("创建rabbitmq连接失败",e);
        }
        return mqttClient;
    }
}
